#include "StdAfx.h"
#include "EphemWrapper.h"
#include "CustomException.h"

#include "EphemDE.h"
#include "EphemEPM.h"

// ====================================== //

CEphemWrapper::CEphemWrapper(LPCTSTR stzEphemPath, eWorkType eType)
{
	switch(eType)
	{
	case eEPM:
		{
			CEphemEPM * pEpm = NULL;
			try
			{
				pEpm = new CEphemEPM(stzEphemPath);
			}
			catch(const CEphemEPM::CError &e)
			{
				throw CCustomException(_T("Error loading EMP ephemerides: %s"), e.GetError());
			}
			m_pInnerEphem = IGetCoordPtr(pEpm);
		}
		break;
	case eDE:
		{
			CEphemDE * pDE = new CEphemDE(stzEphemPath);
			m_pInnerEphem = IGetCoordPtr(pDE);
		}
		break;
	default:
		throw CCustomException(_T("Unknoun ephemeride type"));
	}
}

CEphemWrapper::~CEphemWrapper(void)
{
}

bool CEphemWrapper::GetCoord(double date, bool bBaryCenter, AllBodies & OutCoords, bool bGetVelocity)
{
	if(m_pInnerEphem.get() == NULL)
		throw CCustomException("Ephemerid is not initialized");

	try
	{
		return m_pInnerEphem->GetCoord(date, bBaryCenter, OutCoords, bGetVelocity);
	}
	catch(const CEphemEPM::CError &e)
	{
		throw CCustomException("Error from EPM: %s", e.GetError());
	}
	return false;
}

CStdString CEphemWrapper::StrDateFromJD(double jd)
{
	CStdString res;
	int year, month, date;
	double daypart;
	DateFromJD(jd, year, month, date, daypart);
	daypart += date;
	res.Format(_T("%04d-%02d-%09.6lf"), year, month, daypart);
	return res;
}

LPCTSTR CEphemWrapper::GetBodyName(eBodies body)
{
	LPCTSTR res = _T("");
	switch (body)
	{
	case eMERCURY:
		res = _T("MERCURY");
		break;
	case eVENUS:
		res = _T("VENUS");
		break;
	case eEARTH :
		res = _T("EARTH");
		break;
	case eMARS:
		res = _T("MARS");
		break;
	case eJUPITER:
		res = _T("JUPITER");
		break;
	case eSATURN:
		res = _T("SATURN");
		break;
	case eURANUS:
		res = _T("URANUS");
		break;
	case eNEPTUNE:
		res = _T("NEPTUNE");
		break;
	case ePLUTO:
		res = _T("PLUTO");
		break;
	case eMOON:
		res = _T("MOON");
		break;
	case eSUN:
		res = _T("SUN");
		break;
	default:
		res = _T("Unknoun");
	}
	return res;
}

bool  CEphemWrapper::DateFromJD(double tjd, int &year, int &month, int &date, double &daypart)
{
	int j;
	int calendar_type = 0;
	/* From Explanatory Supplement to Astronomical Almanac, pp. 604, 606 */
	int I, J, K, L, N, D, M, Y;

	tjd += 0.5;
	j = (int)tjd;  /* Integer Julian Day */
	daypart = (tjd - j);

	/*
	Julian calendar.  Explanatory Supplement to Astronomical Alamanac, p. 606.
	If automatic, use Julian calendar for dates before 15 October 1582.
	*/
	if (calendar_type == -1 || (calendar_type == 0 && j <= 2299160)) 
	{
		J = j + 1402;
		K = (J - 1) / 1461;
		L = J - 1461 * K;
		N = (L - 1) / 365 - L / 1461;
		I = L - 365 * N + 30;
		J = (80 * I) / 2447;
		D = I - (2447 * J) / 80;
		I = J / 11;
		M = J + 2 - 12 * I;
		Y = 4 * K + N + I - 4716;
	}
	/*
	Gregorian calendar.
	*/
	else  /* Explanatory Supplement to Astronomical Almanac, p. 604 */
	{	
		L = j + 68569;
		N = (4 * L) / 146097;
		L = L - (146097 * N + 3) / 4;
		I = (4000 * (L + 1)) / 1461001;
		L = L - (1461 * I) / 4 + 31;
		J = (80 * L) / 2447;
		D = L - (2447 * J) / 80;
		L = J / 11;
		M = J + 2 - 12 * L;
		Y = 100 * (N - 49) + I + L;
	}

	year = Y;
	month = M;
	date = D;

	return true;
}

const double CEphemWrapper::s_dKmInAu = 0.149597870699626200e+09;
const double CEphemWrapper::s_dSecInDay = 3600 * 24;

double CEphemWrapper::AUtoKM(double au)
{
	return s_dKmInAu * au;
}

double CEphemWrapper::KMtoAU(double km)
{
	return km / s_dKmInAu;
}

double CEphemWrapper::AUDtoMS(double dAUperDay)
{
	return dAUperDay * (s_dKmInAu * 1000.0) / s_dSecInDay;
}	

double CEphemWrapper::MStoAUD(double dMperSec)
{
	return dMperSec * s_dSecInDay / ( s_dKmInAu * 1000.0);
}

